#pragma once

#include "config.h"

#include <sdbusplus/bus.hpp>
#include <sdbusplus/server.hpp>

#include <string>

namespace phosphor
{
namespace led
{
namespace fru
{
namespace fault
{
namespace monitor
{

/** @brief Assert or deassert an LED based on the input FRU
 *  @param[in] bus       -  The Dbus bus object
 *  @param[in] path      -  Inventory path of the FRU
 *  @param[in] assert    -  Assert if true deassert if false
 */
void action(sdbusplus::bus_t& bus, const std::string& path, bool assert);

/** @class Remove
 *  @brief Implementation of LED handling after resolution of FRU fault
 *  @details Implement methods for watching the resolution of FRU faults
 *  and deasserting corresponding LED.
 */
class Remove
{
  public:
    Remove() = delete;
    ~Remove() = default;
    Remove(const Remove&) = delete;
    Remove& operator=(const Remove&) = delete;
    Remove(Remove&&) = default;
    Remove& operator=(Remove&&) = default;

    /** @brief constructs Remove
     *  @param[in] bus  -  The Dbus bus object
     *  @param[in] path -  Inventory path to fru
     */
    Remove(sdbusplus::bus_t& bus, const std::string& path) :
        inventoryPath(path),
        matchRemoved(bus, match(path),
                     [this](sdbusplus::message_t& m) { removed(m); })
    {
        // Do nothing
    }

  private:
    /** @brief inventory path of the FRU */
    std::string inventoryPath;

    /** @brief sdbusplus signal matches for fault removed */
    sdbusplus::bus::match_t matchRemoved;

    /** @brief Callback function for fru fault created
     *  @param[in] msg       - Data associated with subscribed signal
     */
    void removed(sdbusplus::message_t& msg);

    /** @brief function to create fault remove match for a fru
     *  @param[in] path  - Inventory path of the faulty unit.
     */
    static std::string match(const std::string& path)
    {
        namespace MatchRules = sdbusplus::bus::match::rules;

        std::string matchStmt =
            MatchRules::interfacesRemoved() +
            MatchRules::argNpath(0, path + "/" + CALLOUT_REV_ASSOCIATION);

        return matchStmt;
    }
};

/** @class Add
 *  @brief Implementation of LED handling during FRU fault
 *  @details This implements methods for watching for a FRU fault
 *  being logged to assert the corresponding LED
 */
class Add
{
  public:
    Add() = delete;
    ~Add() = default;
    Add(const Add&) = delete;
    Add& operator=(const Add&) = delete;
    Add(Add&&) = default;
    Add& operator=(Add&&) = default;

    /** @brief constructs Add a watch for FRU faults.
     *  @param[in] bus -  The Dbus bus object
     */
    explicit Add(sdbusplus::bus_t& bus) :
        matchCreated(bus,
                     sdbusplus::bus::match::rules::interfacesAdded() +
                         sdbusplus::bus::match::rules::path_namespace(
                             "/xyz/openbmc_project/logging"),
                     [this](sdbusplus::message_t& m) { created(m); })
    {
        processExistingCallouts(bus);
    }

  private:
    /** @brief sdbusplus signal match for fault created */
    sdbusplus::bus::match_t matchCreated;

    std::vector<std::unique_ptr<Remove>> removeWatches;

    /** @brief Callback function for fru fault created
     *  @param[in] msg       - Data associated with subscribed signal
     */
    void created(sdbusplus::message_t& msg);

    /** @brief This function process all callouts at application start
     *  @param[in] bus - The Dbus bus object
     */
    void processExistingCallouts(sdbusplus::bus_t& bus);
};
} // namespace monitor
} // namespace fault
} // namespace fru
} // namespace led
} // namespace phosphor
